using EFCoreEnterpriseDemo.Builders;
using EFCoreEnterpriseDemo.Data;
using EFCoreEnterpriseDemo.Extensions;
using EFCoreEnterpriseDemo.Models;
using Microsoft.EntityFrameworkCore;

namespace EFCoreEnterpriseDemo.Services
{
    public interface IUserService
    {
        Task<int> CreateUserAsync(CreateUserDto dto);

        Task<PagedResult<UserDto>> GetUsersAsync(UserSearchCriteria criteria);

        Task<UserDto?> GetUserByIdAsync(int id);

        Task UpdateUserAsync(int id, UpdateUserDto dto);

        Task SoftDeleteUserAsync(int id);

        Task RestoreUserAsync(int id);

        Task<byte[]> ExportUsersAsync(UserExportCriteria criteria);

        Task<ImportResult<User>> ImportUsersAsync(System.IO.Stream excelStream);
    }

    public class UserService : IUserService
    {
        private readonly ApplicationDbContext _context;
        private readonly IDataPermissionService _permissionService;

        public UserService(ApplicationDbContext context, IDataPermissionService permissionService)
        {
            _context = context;
            _permissionService = permissionService;
        }

        public async Task<int> CreateUserAsync(CreateUserDto dto)
        {
            var user = new User
            {
                Name = dto.Name,
                Email = dto.Email,
                Phone = dto.Phone,
                Salary = dto.Salary,
                IsActive = true,
                DepartmentId = dto.DepartmentId,
                TenantId = _permissionService.GetCurrentTenantId()
            };

            _context.Users.Add(user);
            await _context.SaveChangesAsync();
            return user.Id;
        }

        public async Task<PagedResult<UserDto>> GetUsersAsync(UserSearchCriteria criteria)
        {
            var query = new QueryBuilder<User>(_context)
                .IncludeDeleted(criteria.IncludeDeleted)
                .WhereIf(criteria.DepartmentId.HasValue, u => u.DepartmentId == criteria.DepartmentId)
                .WhereIf(!string.IsNullOrEmpty(criteria.Keyword), u =>
                    (!string.IsNullOrEmpty(u.Name) && u.Name.Contains(criteria.Keyword!))
                    || (!string.IsNullOrEmpty(u.Email) && u.Email.Contains(criteria.Keyword!)))
                .WhereIf(criteria.IsActive.HasValue, u => u.IsActive == criteria.IsActive)
                .Build();

            var result = await query
                .Select(u => new UserDto
                {
                    Id = u.Id,
                    Name = u.Name,
                    Email = u.Email,
                    Phone = u.Phone,
                    IsActive = u.IsActive,
                    DepartmentName = u.Department == null ? null : u.Department.Name,
                    CreatedAt = u.CreatedAt
                })
                .ToPagedResultAsync(criteria.Page, criteria.PageSize);

            return result;
        }

        public async Task<UserDto?> GetUserByIdAsync(int id)
        {
            var user = await _context.Users
                .Include(u => u.Department)
                .FirstOrDefaultAsync(u => u.Id == id);

            return user == null ? null : new UserDto
            {
                Id = user.Id,
                Name = user.Name,
                Email = user.Email,
                Phone = user.Phone,
                IsActive = user.IsActive,
                DepartmentName = user.Department?.Name,
                CreatedAt = user.CreatedAt
            };
        }

        public async Task UpdateUserAsync(int id, UpdateUserDto dto)
        {
            var user = await _context.Users.FindAsync(id);
            if (user == null) throw new KeyNotFoundException("User not found");

            user.Name = dto.Name;
            user.Email = dto.Email;
            user.Phone = dto.Phone;
            user.Salary = dto.Salary;
            user.DepartmentId = dto.DepartmentId;

            await _context.SaveChangesAsync();
        }

        public async Task SoftDeleteUserAsync(int id)
        {
            var user = await _context.Users.FindAsync(id);
            if (user != null)
            {
                _context.Users.Remove(user);
                await _context.SaveChangesAsync();
            }
        }

        public async Task RestoreUserAsync(int id)
        {
            await _context.RestoreAsync<User>(id);
        }

        public async Task<byte[]> ExportUsersAsync(UserExportCriteria criteria)
        {
            throw new NotImplementedException();
            //var query = new QueryBuilder<User>(_context)
            //    .WhereIf(string.IsNullOrEmpty(criteria.DepartmentId), u => u.DepartmentId == criteria.DepartmentId)
            //    .WhereIf(!string.IsNullOrEmpty(criteria.Keyword), u =>
            //        u.Name.Contains(criteria.Keyword) || u.Email.Contains(criteria.Keyword))
            //    .Build();

            //var users = await query.ToListAsync();

            //using var package = new OfficeOpenXml.ExcelPackage();
            //var worksheet = package.Workbook.Worksheets.Add("Users");

            //await worksheet.LoadFromCollectionAsync(users, true);
            //worksheet.Cells.AutoFitColumns();

            //return package.GetAsByteArray();
        }

        public async Task<ImportResult<User>> ImportUsersAsync(System.IO.Stream excelStream)
        {
            throw new NotImplementedException();
            //using var package = new OfficeOpenXml.ExcelPackage(excelStream);
            //var worksheet = package.Workbook.Worksheets[0];

            //var users = worksheet.ConvertSheetToObjects<User>().ToList();
            //var result = new ImportResult<User>();

            //foreach (var (user, index) in users.Select((u, i) => (u, i)))
            //{
            //    var validation = ValidateUser(user);
            //    if (!validation.IsValid)
            //    {
            //        result.Errors.Add(new ImportError<User>
            //        {
            //            Item = user,
            //            RowNumber = index + 2,
            //            ErrorMessage = validation.ErrorMessage
            //        });
            //        continue;
            //    }

            //    result.SuccessItems.Add(user);
            //}

            //if (result.SuccessItems.Any())
            //{
            //    await _context.BulkInsertAsync(result.SuccessItems);
            //}

            //return result;
        }

        private ValidationResult ValidateUser(User user)
        {
            if (string.IsNullOrEmpty(user.Name))
                return ValidationResult.Error("Name is required");

            if (string.IsNullOrEmpty(user.Email))
                return ValidationResult.Error("Email is required");

            return ValidationResult.Success();
        }
    }

    // DTOs
    public class CreateUserDto
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public string Phone { get; set; }
        public decimal Salary { get; set; }
        public int DepartmentId { get; set; }
    }

    public class UpdateUserDto
    {
        public string? Name { get; set; }
        public string? Email { get; set; }
        public string? Phone { get; set; }
        public decimal? Salary { get; set; }
        public int? DepartmentId { get; set; }
    }

    public class UserDto
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public string? Email { get; set; }
        public string? Phone { get; set; }
        public bool IsActive { get; set; }
        public string? DepartmentName { get; set; }
        public DateTime CreatedAt { get; set; }
    }

    public class UserSearchCriteria : PagedCriteria
    {
        public string? Keyword { get; set; }
        public int? DepartmentId { get; set; }
        public bool? IsActive { get; set; }
        public bool IncludeDeleted { get; set; } = false;
    }

    public class UserExportCriteria
    {
        public int? DepartmentId { get; set; }
        public string? Keyword { get; set; }
    }
}